#include"threadpool.h"
#include<stdlib.h>
#include<stdio.h>
// typedef struct task_queue
// {
//     void (*routine)(void*);
//     void *arg;
//     struct task_queue *next;
// }task_queue_t;

// typedef struct threadpool

// {
//     int shutdown;   //是否消耗
//     int max_thread_num;//最大数量
//     pthread_t *thread_ids;//线程id数组首地址
//     task_queue_t *head;//任务队列队首
//     task_queue_t *tail;//任务队列队尾
//     pthread_mutex_t queue_lock;
//     pthread_cond_t queue_ready;s
// }threadpool_t;

static threadpool_t *threadpool;

static void *thread_routine(void *arg)
{
    task_queue_t *task;
    while (1)
    {
        pthread_mutex_trylock(&threadpool->queue_lock);
        while ((threadpool->head ==NULL)&&(!threadpool->shutdown))
        {
            pthread_cond_wait(&threadpool->queue_ready,&threadpool->queue_lock);
        }
        if(threadpool->shutdown)
        {
            pthread_mutex_unlock(&threadpool->queue_lock);
            pthread_exit(NULL);
        }
        task=threadpool->head;
        threadpool->head=threadpool->head->next;
        pthread_mutex_unlock(&threadpool->queue_lock);
        task->routine(task->arg);
        free(task->arg);
        free(task);
    }
    return NULL;
    
}
int threadpool_create(int num)
{
    threadpool=calloc(1,sizeof(threadpool_t));
     if(threadpool == NULL)
    {
        perror("calloc error\n");
        exit(1);
    }
    threadpool->thread_ids=(pthread_t*)malloc(sizeof(pthread_t)*num);
    if(threadpool->thread_ids == NULL)
    {
        perror("malloc error\n");
        exit(1);
    }
    threadpool->shutdown=0;
    threadpool->head=NULL;
    threadpool->tail=NULL;
    threadpool->max_thread_num=num;
    if((pthread_mutex_init(&threadpool->queue_lock,NULL)!=0))
    {
        perror("queue_lock init error\n");
        exit(1);
    }
    if((pthread_cond_init(&threadpool->queue_ready,NULL)!=0))
    {
        perror("queue_ready init error\n");
        exit(1);
    }

    for(int i = 0;i<threadpool->max_thread_num;i++)
    {
        if(pthread_create(&threadpool->thread_ids[i],NULL,thread_routine,NULL)!=0)
        {
            perror("pthread_create init error\n");
            exit(1);
        }
    }
    return 0;
}

int threadpool_add_task(void * (*routine)(void*),void *arg)
{
    task_queue_t *task;
    if(!routine)
    {
        perror("invalid arg\n");
        exit(1);
    }
    task=malloc(sizeof(task_queue_t));
    task->arg=arg;
    task->next=NULL;
    task->routine=routine;
    pthread_mutex_lock(&threadpool->queue_lock);
    if(threadpool->head==NULL)
    {
        threadpool->head=task;
        threadpool->tail=task;
    }
    else
    {
        threadpool->tail->next=task;
        threadpool->tail=task;
    }
    pthread_cond_broadcast(&threadpool->queue_ready);
    pthread_mutex_unlock(&threadpool->queue_lock);
    return 0;

}
void threadpool_destroy()
{
    int i;
    task_queue_t *temp;
    if(threadpool->shutdown)
    {
        return;
    }
    threadpool->shutdown=1;
    pthread_mutex_lock(&threadpool->queue_lock);
    pthread_cond_broadcast(&threadpool->queue_ready);
    pthread_mutex_unlock(&threadpool->queue_lock);

    for(int i=0;i<threadpool->max_thread_num;i++)
    {
        pthread_join(threadpool->thread_ids[i],NULL);
    }

    free(threadpool->thread_ids);
    pthread_mutex_destroy(&threadpool->queue_lock);
    pthread_cond_destroy(&threadpool->queue_ready);
    free(threadpool);
}